package com.android.readcard.server;

import android.util.Log;

import com.android.readcard.utils.djlm.DJLMReader3.reader.HexUtil;

import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 2017/3/29.
 */
/////////////////////////////////////
    /*
	安全模块与身份证通讯的指令条目
    */
public  class CommandItem {
    public static final int STATE_COMMAND_NOREADY = 0; //指令未准备好
    public static final int STATE_COMMAND_READY = 1;//指令已准备好
    public static final int STATE_COMMAND_RUNING = 2;//指令正在传输运行
    public static final int STATE_COMMAND_FINISH = 3;//指令传输执行已结束
    public static final int STATE_COMMAND_USEED = 4;//指令已使用

    public static final int COMMAND_FIND_CARD = 0;//身份证寻卡指令
    public static final int COMMAND_SELECT_CARD = 1;//身份证选择卡片指令
    public static final int COMMAND_SELECT_FILE = 2;//COS系统文件选择指令
    public static final int COMMAND_READ_BINARY = 3;//COS系统二进制读取指令
    public static final int COMMAND_GET_CHALLENGE = 4;//COS系统获取随机码指令
    public static final int COMMAND_INTERNAL_AUTHENTICATE = 5;//COS系统内部验证指令
    public static final int COMMAND_EXTERNAL_AUTHENTICATE = 6;//COS系统外边验证指令

    public byte[] m_Query; //请求命令
    byte[] m_QueryMatchMask; //请求验证匹配模板
    public byte[] m_Response;//返回的响应内容
    public int m_nResponseLen;//最大响应长度
    public byte[] m_bFixResponse;//是否为固定响应（在正确返回的情况下）
    public int m_nComandState;//指令状态
    public int m_nDefaultState;//指令初始状态
    public int m_nCommandType;//指令类型
    public int m_nQueryCount = 0;//次数请求
    public int m_nRunCount = 0;//运行此时
    public int m_nCachePos = 0;
    public int m_nStep = 0;

    public CommandItem() {
        m_nQueryCount = 0;
        m_nRunCount = 0;
        m_Response = null;
    }

    static void LogOut(String strTest)
    {
        Log.i("CommandItem", strTest);
        //log.info(strTest);
        //System.out.println(strTest);
    }

    //获得指令当前状态
    public int GetSatet() {
        return m_nComandState;
    }

    //切换至下一状态
    public void NextState() {
        //if (m_nComandState !=STATE_COMMAND_USEED)
        m_nComandState++;
    }

    //匹配判断是否为当前指令
    public boolean QueryMatch(byte[] query) {
        boolean bMatch = true;
        if (query.length != m_Query.length)
            return false;
        for (int i = 0; i < m_QueryMatchMask.length; i++) {
            if (m_QueryMatchMask[i] != query[i])
                bMatch = false;
        }
        //byte [] subQuery = Arrays.copyOf(query, m_nQueryMatchLen);
        //return  Arrays.equals(subQuery, m_Match);
        return bMatch;
    }
    /*
    //判断返回结果是否正确
    boolean IsResponseOK(byte[] response) {
    	if (response != null && response.length == m_nResponseLen)
    	{
	        if (m_nCommandType == COMMAND_FIND_CARD) {
	            if (response[0] == 0x50)
	                return true;
	        } else if (m_nCommandType == COMMAND_SELECT_CARD) {
	            if (response[0] == 0x08)
	                return true;
	        } else {
	            if (response[response.length - 2] == (byte) 0x90 && response[response.length - 1] == 0x00)
	                return true;
	        }
    	}
        return false;
    }

    void Fix() {}

    String GetDebugString(byte[] data)
    {
        return HexUtil.bytesToHexString(data);
    }
    */

    public boolean IsResponseOK(byte[] response) {
        if (response != null && response.length == m_nResponseLen)
        {
            if (m_nCommandType == COMMAND_FIND_CARD) {
                if (response[4] == '5' && response[5] == '0')
                    return true;
            } else if (m_nCommandType == COMMAND_SELECT_CARD) {
                if (response[4] == '0' && response[5] == '8')
                    return true;
            } else {
                if (response[response.length - 5] == '9' && response[response.length - 4] == '0' && response[response.length - 3] == '0' && response[response.length - 2] == '0')
                    return true;
            }
        }
        return false;
    }

    void Fix()
    {
        m_Query = QueryBytesToStrig(m_Query, m_Query.length);
        m_QueryMatchMask = QueryBytesToStrig(m_QueryMatchMask, m_QueryMatchMask.length);
        m_QueryMatchMask = Arrays.copyOf(m_QueryMatchMask, m_QueryMatchMask.length - 1);
        if (m_bFixResponse != null)
            m_bFixResponse = ResponseBytesToString(m_bFixResponse, m_bFixResponse.length);
        m_nResponseLen = m_nResponseLen * 2 + 5;
    }

    public String GetDebugString(byte[] data)
    {
        if (data != null)
            return new String(data);
        else
            return null;
    }

    public boolean IsResponseOK() {
        return (IsResponseOK(m_Response));
    }

    //构造寻卡指令
    static CommandItem MakeCardFindCommand() {
        byte[] query = new byte[]{0x05, 0x00, 0x00};
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = query;
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = null;
        commChannel.m_nResponseLen = 12;
        commChannel.m_nCommandType = CommandItem.COMMAND_FIND_CARD;
        //commChannel.m_Query = ("f " + HexUtil.bytesToHexString(query) + "\n").getBytes();
        return commChannel;
    }

    //构造选择卡片指令
    static CommandItem MakeCardSelectCommand() {
        byte[] query = new byte[]{0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x08};
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = query;
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = new byte[]{0x08};
        commChannel.m_nResponseLen = 1;
        commChannel.m_nCommandType = CommandItem.COMMAND_SELECT_CARD;
        return commChannel;
    }

    //构造COS文件选择指令
    static CommandItem Make_SELECT_FileCommand(int nFileID) {
        byte[] query = new byte[]{0x00, (byte) 0xA4, 0x00, 0x00, 0x02, 0x60, 0x02};
        query[5] = (byte) ((nFileID >> 8) & 0xff);
        query[6] = (byte) ((nFileID) & 0xff);
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = query;
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = new byte[]{(byte) 0x90, 0x00};
        commChannel.m_nResponseLen = 2;
        commChannel.m_nCommandType = CommandItem.COMMAND_SELECT_FILE;
        return commChannel;
    }

    //构造COS文件二进制读取指令
    static CommandItem Make_READ_BINARY_Command(int nPos, int nLen) {
        byte[] query = new byte[]{(byte) 0x80, (byte) 0xB0, 0x00, 0x00, 0x00};
        query[2] = (byte) ((nPos >> 8) & 0xff);
        query[3] = (byte) ((nPos) & 0xff);
        query[4] = (byte) nLen;
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = query;
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = null;
        commChannel.m_nResponseLen = nLen + 2;
        commChannel.m_nCommandType = CommandItem.COMMAND_READ_BINARY;
        return commChannel;
    }

    //构造随机码获取指令
    static CommandItem Make_GET_CHALLENGE_Command() {
        byte[] query = new byte[]{0x00, (byte) 0x84, 0x00, 0x00, 0x08};
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = query;
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = null;
        commChannel.m_nResponseLen = 8 + 2;
        commChannel.m_nCommandType = CommandItem.COMMAND_GET_CHALLENGE;
        return commChannel;
    }

    //构造内部验证指令
    static CommandItem Make_INTERNAL_AUTHENTICATE_Command(byte[] data) {
        byte[] query = new byte[15];
        System.arraycopy(new byte[]{0x00, (byte) 0x88, 0x00, 0x52, 0x0A, (byte) 0xF0, 0x00}, 0, query, 0, 7);
        if (data != null)
            System.arraycopy(data, 0, query, 7, 8);
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_NOREADY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        if (data != null)
            commChannel.m_nComandState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = Arrays.copyOf(query, 7);
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = null;
        commChannel.m_nResponseLen = 8 + 2;
        commChannel.m_nCommandType = CommandItem.COMMAND_INTERNAL_AUTHENTICATE;
        return commChannel;
    }

    //构造外部验证指令
    static CommandItem Make_EXTERNAL_AUTHENTICATE_Command(byte[] data) {
        byte[] query = new byte[15];
        System.arraycopy(new byte[]{0x00, (byte) 0x82, 0x00, 0x52, 0x0A, (byte) 0xF0, 0x01}, 0, query, 0, 7);
        if (data != null)
            System.arraycopy(data, 0, query, 7, 8);
        CommandItem commChannel = new CommandItem();
        commChannel.m_nDefaultState = CommandItem.STATE_COMMAND_NOREADY;
        commChannel.m_nComandState = commChannel.m_nDefaultState;
        if (data != null)
            commChannel.m_nComandState = CommandItem.STATE_COMMAND_READY;
        commChannel.m_Query = query;
        commChannel.m_QueryMatchMask = Arrays.copyOf(query, 7);
        commChannel.m_Response = null;
        commChannel.m_bFixResponse = new byte[]{(byte) 0x90, 0x00};
        commChannel.m_nResponseLen = 2;
        commChannel.m_nCommandType = CommandItem.COMMAND_EXTERNAL_AUTHENTICATE;
        return commChannel;
    }

    public static byte[] InitCommandList(List<CommandItem> commandList) {
        commandList.clear();
        commandList.add(MakeCardFindCommand());
        commandList.add(MakeCardSelectCommand());
        AddReadBinFileCommandList(commandList, 0x6002, 32, 16);
        commandList.add(Make_INTERNAL_AUTHENTICATE_Command(null));
        commandList.add(Make_GET_CHALLENGE_Command());
        commandList.add(Make_EXTERNAL_AUTHENTICATE_Command(null));
        AddReadBinFileCommandList(commandList, 0x6011, 214, 16);
        AddReadBinFileCommandList(commandList, 0x6012, 256, 16);
        AddReadBinFileCommandList(commandList, 0x6013, 1024, 16);
        AddReadBinFileCommandList(commandList, 0x6021, 1024, 16);
        ////////////////////////////////////////////////
        Fix(commandList);
        int nPos = 0;
        for (int i = 0; i < commandList.size(); i++) {
            CommandItem commChannel = commandList.get(i);
            commChannel.m_nCachePos = nPos;
            nPos += commChannel.m_nResponseLen;
            commChannel.m_nStep = i;
            //LogOut("f "+ HexUtil.bytesToHexString(commChannel.m_Query));
            //LogOut("r 819000");
        }
        LogOut("cache reset!");
        return new byte[nPos];
    }

    //构造二进制文件读取的指令列表
    static void AddReadBinFileCommandList(List<CommandItem> commandList, int nFileID, int nLen, int nPerLen) {
        int nReadLen = 0;
        commandList.add(Make_SELECT_FileCommand(nFileID));
        while (nReadLen < nLen) {
            int nThisReadLen = nLen - nReadLen;
            if (nThisReadLen > nPerLen)
                nThisReadLen = nPerLen;
            commandList.add(Make_READ_BINARY_Command(nReadLen, nThisReadLen));
            nReadLen += nThisReadLen;
        }
    }

    static void Fix(List<CommandItem> commandList)
    {
        for (int i = 0; i < commandList.size(); i++) {
            CommandItem commChannel = commandList.get(i);
            commChannel.Fix();
        }
    }

    public static byte[] QueryStrigToBytes(byte[] buff, int nLen)
    {
        byte[] Query = null;
        if (buff != null && buff.length >= 2 && nLen >= 2) {
            String message = new String(buff, 0, nLen);
            Query = HexUtil.hexStringToBytes(message.substring(2).trim());
        }
        return Query;
    }

    public static byte[] QueryBytesToStrig(byte[] data, int nLen)
    {
        if (data != null)
        {
            String str = null;
            str = "f " + HexUtil.bytesToHexString(data, nLen) + "\n";
            return str.getBytes();
        }
        return null;
    }

    public static byte[] ResponseStringToBytes(byte[] ret, int nLen)
    {
        byte[] send = null;
        if (ret != null && ret.length >= 4 && nLen >= 4)
        {
            String message = new String(ret, 0, nLen);
            if (message.length() > 4)
                send = HexUtil.hexStringToBytes(message.substring(4).trim());
            else if (message.length() == 4)
                send = new byte[]{};
        }
        return send;
    }

    public static byte[] ResponseBytesToString(byte[] Ret, int nLen)
    {
        if (Ret != null) {
            //LogOut("rev:"+HexUtil.bytesToHexString(Ret));
            String str = null;
            if (Ret.length > 0)
                str = "r 81" + HexUtil.bytesToHexString(Ret, nLen) + "\n";
            else
                str = "r 84\n";
            //LogOut("BLE Rx:" + str);
            return str.getBytes();
        }
        return null;
    }
}
